#include <pthread.h>
#include <iostream>
#include <queue>
// 单例模式（这里是饿汉模式）(条件变量的队列处理任务)
#define _MAX 5;
template <class T>
class Pthread_Pool
{
private:
    std::queue<T> _q;
    pthread_mutex_t _mtx;
    pthread_mutex_t _create_mtx;
    pthread_cond_t _cond;
    static int _max;
    static Pthread_Pool *_self;
    Pthread_Pool()
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    Pthread_Pool(const Pthread_Pool &pool) {}
    ~Pthread_Pool()
    {
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_cond);
    }
    static void *Work(void *argv)
    {
        while (true)
        {
            Pthread_Pool *self = (Pthread_Pool *)argv;
            self->Lock();
            if (self->_q.empty())
            {
                self->Wait();
            }
            // 一定有任务
            T task = self->_q.front();
            self->_q.pop();
            // 拿到任务放开锁
            self->UnLock();
            // 开始完成任务
            task->run();
        }
    }
    void Pthread_Create()
    {
        pthread_t tmp_work[_max];
        for (int i = 0; i < _max; ++i)
        {
            pthread_create(tmp_work + i, nullptr, Work, (void *)this);
        }
        pthread_t tmp_create[_max];
    }
    void Lock()
    {
        pthread_mutex_lock(&_mtx);
    }
    void UnLock()
    {
        pthread_mutex_unlock(&_mtx);
    }
    void Wait()
    {
        pthread_cond_wait(&_cond, &_mtx);
    }
    void WakeUp()
    {
        pthread_cond_signal(&_cond);
    }

public:
    // 可能传指针，不能用引用
    static void GetWork(T task)
    {
        Pthread_Pool *self = Pthread_Pool::InitPthreadPool();
        self->Lock();
        self->_q.push(task);
        self->UnLock();
        self->WakeUp();
    }
    static Pthread_Pool *InitPthreadPool()
    {
        if (_self == nullptr)
        {
            static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
            pthread_mutex_lock(&mtx);
            if (_self == nullptr)
            {
                _self = new Pthread_Pool();
            }
            _self->Pthread_Create();
            pthread_mutex_unlock(&mtx);
        }
        return _self;
    }
};
template <class T>
int Pthread_Pool<T>::_max = _MAX;
template <class T>
Pthread_Pool<T> *Pthread_Pool<T>::_self = nullptr;
